Setup
library(magrittr)
library(tidyverse)
library(glue)
library(arrow)
library(matric)
batch <- params$batch
futile.logger::flog.info(glue("Batch = {batch}"))
INFO [2021-05-05 22:13:44] Batch = 2020_11_04_CPJUMP1
experiment <- as.data.frame(params$experiment)
futile.logger::flog.info(glue("Experiment = {experiment}"))
INFO [2021-05-05 22:13:44] Experiment = Standard
INFO [2021-05-05 22:13:44] Experiment = Compound
INFO [2021-05-05 22:13:44] Experiment = U2OS
INFO [2021-05-05 22:13:44] Experiment = 48
data_level <- params$data_level
futile.logger::flog.info(glue("Data level = {data_level}"))
INFO [2021-05-05 22:13:44] Data level = normalized
if (params$normalization == "whole_plate") {
norm_suffix <- ""
} else if (params$normalization == "negcon") {
norm_suffix <- "_negcon"
}
sprintf("Normalization = %s. Using suffix = '%s'", params$normalization, norm_suffix)
[1] "Normalization = negcon. Using suffix = '_negcon'"
Normalization = negcon. Using suffix = '_negcon'
filename_prefix_profiles <- glue("{batch}_all_{data_level}{norm_suffix}")
Load
parquet_file_recoded <-
glue("{batch}/{filename_prefix_profiles}_recoded_aggregated.parquet")
if (file.exists(parquet_file_recoded) && !params$force_recompute) {
parquet_file <- parquet_file_recoded
futile.logger::flog.info(glue("Loading {parquet_file} ..."))
stopifnot(file.exists(parquet_file))
profiles <-
read_parquet(parquet_file)
variables <-
str_subset(names(profiles), "Metadata_", negate = TRUE)
} else {
parquet_file <-
glue("../collated/{batch}/{filename_prefix_profiles}.parquet")
futile.logger::flog.info(glue("Loading {parquet_file} ..."))
stopifnot(file.exists(parquet_file))
profiles <-
read_parquet(parquet_file)
# if(!is.null(experiment)) {
# profiles <- profiles %>% inner_join(experiment)
# }
variables <-
str_subset(names(profiles), "Metadata_", negate = TRUE)
metadata_cols <-
str_subset(names(profiles), "Metadata_")
variables <-
params$variable_groups %>%
unlist() %>%
map(function(pattern)
str_subset(variables, pattern = pattern)) %>%
unlist()
profiles <-
profiles %>%
select(all_of(c(metadata_cols, variables)))
variables <-
str_subset(names(profiles), "Metadata_", negate = TRUE)
profiles <-
profiles %>%
group_by(across(params$strata_replicate)) %>%
summarize(across(all_of(variables), median),
.groups = "keep")
attr(profiles, "variable_groups") <- params$variable_groups
parquet_file <-
parquet_file_recoded
futile.logger::flog.info(glue("Writing {parquet_file} ..."))
profiles %>%
write_parquet(parquet_file,
compression = "gzip",
compression_level = 9)
}
INFO [2021-05-05 22:13:44] Loading 2020_11_04_CPJUMP1/2020_11_04_CPJUMP1_all_normalized_negcon_recoded_aggregated.parquet ...
Plot
profiles_enriched %>%
inner_join(experiment) %>%
pivot_longer(-matches("Metadata"),
names_to = "feature_group")%>%
ggplot(aes(feature_group, value)) +
geom_boxplot() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
Joining, by = c("Metadata_experiment_condition", "Metadata_experiment_type", "Metadata_cell_line", "Metadata_timepoint")

profiles_enriched %>%
inner_join(experiment) %>%
pivot_longer(-matches("Metadata"),
names_to = "feature_group") %>%
ggplot(aes(feature_group, value, group = Metadata_Well)) +
geom_line(alpha = .09) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
facet_wrap(~Metadata_negcon_or_other, ncol = 1)
Joining, by = c("Metadata_experiment_condition", "Metadata_experiment_type", "Metadata_cell_line", "Metadata_timepoint")

library(plotly)
Attaching package: 'plotly'
The following object is masked from 'package:arrow':
schema
The following object is masked from 'package:ggplot2':
last_plot
The following object is masked from 'package:stats':
filter
The following object is masked from 'package:graphics':
layout
df <-
profiles_enriched %>%
inner_join(experiment)
Joining, by = c("Metadata_experiment_condition", "Metadata_experiment_type", "Metadata_cell_line", "Metadata_timepoint")
dimensions <- list(
list(label = "Intensity_RNA",
values = ~ Intensity_RNA),
list(label = 'Intensity_DNA',
values = ~ Intensity_DNA)
)
dimensions <-
variables_enriched %>%
map(function(variable) {
list(label = variable,
values = df[[variable]])
})
df %>%
plot_ly(width = 1000,
height = 600) %>%
add_trace(type = 'parcoords',
dimensions = dimensions)
LS0tCnRpdGxlOiAiRmVhdHVyZSBhbmFseXNpcyIKcGFyYW1zOgogIGZvcmNlX3JlY29tcHV0ZTogRkFMU0UKICBiYXRjaDogMjAyMF8xMV8wNF9DUEpVTVAxCiAgZGF0YV9sZXZlbDogbm9ybWFsaXplZAogIG5vcm1hbGl6YXRpb246IG5lZ2NvbgogIGV4cGVyaW1lbnQ6IAogICAgdmFsdWU6CiAgICAgIE1ldGFkYXRhX2V4cGVyaW1lbnRfY29uZGl0aW9uOiBTdGFuZGFyZAogICAgICBNZXRhZGF0YV9leHBlcmltZW50X3R5cGU6IENvbXBvdW5kCiAgICAgIE1ldGFkYXRhX2NlbGxfbGluZTogVTJPUwogICAgICBNZXRhZGF0YV90aW1lcG9pbnQ6ICI0OCIKICBuZXN0aW5nX2xldmVsXzA6CiAgICB2YWx1ZToKICAgICAgLSBNZXRhZGF0YV9leHBlcmltZW50X2NvbmRpdGlvbgogICAgICAtIE1ldGFkYXRhX2V4cGVyaW1lbnRfdHlwZQogICAgICAtIE1ldGFkYXRhX2NlbGxfbGluZQogICAgICAtIE1ldGFkYXRhX3RpbWVwb2ludAogIHN0cmF0YV9yZXBsaWNhdGU6CiAgICB2YWx1ZToKICAgICAgLSBNZXRhZGF0YV9leHBlcmltZW50X2NvbmRpdGlvbgogICAgICAtIE1ldGFkYXRhX2V4cGVyaW1lbnRfdHlwZQogICAgICAtIE1ldGFkYXRhX2NlbGxfbGluZQogICAgICAtIE1ldGFkYXRhX3RpbWVwb2ludAogICAgICAtIE1ldGFkYXRhX3BsYXRlX21hcF9uYW1lCiAgICAgIC0gTWV0YWRhdGFfV2VsbAogICAgICAtIE1ldGFkYXRhX2dlbmVzCiAgICAgIC0gTWV0YWRhdGFfcGVydF90eXBlCiAgICAgIC0gTWV0YWRhdGFfY29udHJvbF90eXBlCiAgICAgIC0gTWV0YWRhdGFfUGxhdGVfTWFwX05hbWUKICAgICAgLSBNZXRhZGF0YV9uZWdjb25fY29udHJvbF90eXBlCiAgICAgIC0gTWV0YWRhdGFfdGFyZ2V0X3NlcXVlbmNlCiAgICAgIC0gTWV0YWRhdGFfbWdfcGVyX21sCiAgICAgIC0gTWV0YWRhdGFfbW1vbGVzX3Blcl9saXRlcgogICAgICAtIE1ldGFkYXRhX3NvbHZlbnQKICAgICAgLSBNZXRhZGF0YV90YXJnZXQKICAgICAgLSBNZXRhZGF0YV9wZXJ0X2luYW1lCiAgICAgIC0gTWV0YWRhdGFfYnJvYWRfc2FtcGxlCiAgICAgIC0gTWV0YWRhdGFfcHViY2hlbV9jaWQKICAgICAgLSBNZXRhZGF0YV9JbkNoSUtleQogICAgICAtIE1ldGFkYXRhX2dlbmUKICAgICAgLSBNZXRhZGF0YV9uZWdjb25fb3Jfb3RoZXIKICAgICAgLSBNZXRhZGF0YV9uZWdjb25fY29udHJvbF90eXBlX3RyaW1tZWQKICB2YXJpYWJsZV9ncm91cHM6CiAgICB2YWx1ZToKICAgICAgLSB4QXJlYTogX0FyZWFTaGFwZV9BcmVhJAogICAgICAtIHhTaGFwZTogQXJlYVNoYXBlCiAgICAgIC0geE5laWdoOiBOZWlnaGJvcnMKICAgICAgLSB4Q29ycjogQ29ycmVsYXRpb24KICAgICAgLSBUZXhfQUdQOiAoKFRleHR1cmV8R3JhbnVsYXJpdHl8UmFkaWFsRGlzdHJpYnV0aW9uKV8uKl8oQUdQKSkKICAgICAgLSBUZXhfRE5BOiAoKFRleHR1cmV8R3JhbnVsYXJpdHl8UmFkaWFsRGlzdHJpYnV0aW9uKV8uKl8oRE5BKSkKICAgICAgLSBUZXhfRVI6ICgoVGV4dHVyZXxHcmFudWxhcml0eXxSYWRpYWxEaXN0cmlidXRpb24pXy4qXyhFUikpCiAgICAgIC0gVGV4X01pdG86ICgoVGV4dHVyZXxHcmFudWxhcml0eXxSYWRpYWxEaXN0cmlidXRpb24pXy4qXyhNaXRvKSkKICAgICAgLSBUZXhfUk5BOiAoKFRleHR1cmV8R3JhbnVsYXJpdHl8UmFkaWFsRGlzdHJpYnV0aW9uKV8uKl8oUk5BKSkKICAgICAgLSBJbnRfQUdQOiAoKEludGVuc2l0eSlfLipfKEFHUCkpCiAgICAgIC0gSW50X0ROQTogKChJbnRlbnNpdHkpXy4qXyhETkEpKQogICAgICAtIEludF9FUjogKChJbnRlbnNpdHkpXy4qXyhFUikpCiAgICAgIC0gSW50X01pdG86ICgoSW50ZW5zaXR5KV8uKl8oTWl0bykpCiAgICAgIC0gSW50X1JOQTogKChJbnRlbnNpdHkpXy4qXyhSTkEpKQotLS0KCiMgU2V0dXAKCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdsdWUpCmxpYnJhcnkoYXJyb3cpCmxpYnJhcnkobWF0cmljKQpgYGAKCgpgYGB7cn0KYmF0Y2ggPC0gcGFyYW1zJGJhdGNoCmZ1dGlsZS5sb2dnZXI6OmZsb2cuaW5mbyhnbHVlKCJCYXRjaCA9IHtiYXRjaH0iKSkKYGBgCmBgYHtyfQpleHBlcmltZW50IDwtIGFzLmRhdGEuZnJhbWUocGFyYW1zJGV4cGVyaW1lbnQpCmZ1dGlsZS5sb2dnZXI6OmZsb2cuaW5mbyhnbHVlKCJFeHBlcmltZW50ID0ge2V4cGVyaW1lbnR9IikpCmBgYAoKCmBgYHtyfQpkYXRhX2xldmVsIDwtIHBhcmFtcyRkYXRhX2xldmVsCmZ1dGlsZS5sb2dnZXI6OmZsb2cuaW5mbyhnbHVlKCJEYXRhIGxldmVsID0ge2RhdGFfbGV2ZWx9IikpCmBgYAoKCmBgYHtyfQppZiAocGFyYW1zJG5vcm1hbGl6YXRpb24gPT0gIndob2xlX3BsYXRlIikgewogIG5vcm1fc3VmZml4IDwtICIiCn0gZWxzZSBpZiAocGFyYW1zJG5vcm1hbGl6YXRpb24gPT0gIm5lZ2NvbiIpIHsKICBub3JtX3N1ZmZpeCA8LSAiX25lZ2NvbiIKfQpzcHJpbnRmKCJOb3JtYWxpemF0aW9uID0gJXMuIFVzaW5nIHN1ZmZpeCA9ICclcyciLCBwYXJhbXMkbm9ybWFsaXphdGlvbiwgbm9ybV9zdWZmaXgpCmBgYAoKCmBgYHtyfQpmaWxlbmFtZV9wcmVmaXhfcHJvZmlsZXMgPC0gZ2x1ZSgie2JhdGNofV9hbGxfe2RhdGFfbGV2ZWx9e25vcm1fc3VmZml4fSIpCmBgYAoKIyBMb2FkCgpgYGB7cn0KcGFycXVldF9maWxlX3JlY29kZWQgPC0KICBnbHVlKCJ7YmF0Y2h9L3tmaWxlbmFtZV9wcmVmaXhfcHJvZmlsZXN9X3JlY29kZWRfYWdncmVnYXRlZC5wYXJxdWV0IikKCmlmIChmaWxlLmV4aXN0cyhwYXJxdWV0X2ZpbGVfcmVjb2RlZCkgJiYgIXBhcmFtcyRmb3JjZV9yZWNvbXB1dGUpIHsKICBwYXJxdWV0X2ZpbGUgPC0gcGFycXVldF9maWxlX3JlY29kZWQKICAKICBmdXRpbGUubG9nZ2VyOjpmbG9nLmluZm8oZ2x1ZSgiTG9hZGluZyB7cGFycXVldF9maWxlfSAuLi4iKSkKICAKICBzdG9waWZub3QoZmlsZS5leGlzdHMocGFycXVldF9maWxlKSkKICAKICBwcm9maWxlcyA8LQogICAgcmVhZF9wYXJxdWV0KHBhcnF1ZXRfZmlsZSkKICAKICB2YXJpYWJsZXMgPC0KICAgIHN0cl9zdWJzZXQobmFtZXMocHJvZmlsZXMpLCAiTWV0YWRhdGFfIiwgbmVnYXRlID0gVFJVRSkKICAKfSBlbHNlIHsKICAKICBwYXJxdWV0X2ZpbGUgPC0KICAgIGdsdWUoIi4uL2NvbGxhdGVkL3tiYXRjaH0ve2ZpbGVuYW1lX3ByZWZpeF9wcm9maWxlc30ucGFycXVldCIpCiAgCiAgZnV0aWxlLmxvZ2dlcjo6ZmxvZy5pbmZvKGdsdWUoIkxvYWRpbmcge3BhcnF1ZXRfZmlsZX0gLi4uIikpCiAgCiAgc3RvcGlmbm90KGZpbGUuZXhpc3RzKHBhcnF1ZXRfZmlsZSkpCiAgCiAgcHJvZmlsZXMgPC0KICAgIHJlYWRfcGFycXVldChwYXJxdWV0X2ZpbGUpCiAgCiAgIyBpZighaXMubnVsbChleHBlcmltZW50KSkgewogICMgICBwcm9maWxlcyA8LSBwcm9maWxlcyAlPiUgaW5uZXJfam9pbihleHBlcmltZW50KQogICMgfQogIAogIHZhcmlhYmxlcyA8LQogICAgc3RyX3N1YnNldChuYW1lcyhwcm9maWxlcyksICJNZXRhZGF0YV8iLCBuZWdhdGUgPSBUUlVFKQogIAogIG1ldGFkYXRhX2NvbHMgPC0KICAgIHN0cl9zdWJzZXQobmFtZXMocHJvZmlsZXMpLCAiTWV0YWRhdGFfIikKICAKICB2YXJpYWJsZXMgPC0KICAgIHBhcmFtcyR2YXJpYWJsZV9ncm91cHMgJT4lCiAgICB1bmxpc3QoKSAlPiUKICAgIG1hcChmdW5jdGlvbihwYXR0ZXJuKQogICAgICBzdHJfc3Vic2V0KHZhcmlhYmxlcywgcGF0dGVybiA9IHBhdHRlcm4pKSAlPiUKICAgIHVubGlzdCgpCiAgCiAgcHJvZmlsZXMgPC0KICAgIHByb2ZpbGVzICU+JQogICAgc2VsZWN0KGFsbF9vZihjKG1ldGFkYXRhX2NvbHMsIHZhcmlhYmxlcykpKQogIAogIHZhcmlhYmxlcyA8LQogICAgc3RyX3N1YnNldChuYW1lcyhwcm9maWxlcyksICJNZXRhZGF0YV8iLCBuZWdhdGUgPSBUUlVFKQogIAogIHByb2ZpbGVzIDwtCiAgICBwcm9maWxlcyAlPiUKICAgIGdyb3VwX2J5KGFjcm9zcyhwYXJhbXMkc3RyYXRhX3JlcGxpY2F0ZSkpICU+JQogICAgc3VtbWFyaXplKGFjcm9zcyhhbGxfb2YodmFyaWFibGVzKSwgbWVkaWFuKSwKICAgICAgICAgICAgICAuZ3JvdXBzID0gImtlZXAiKQogIAogIGF0dHIocHJvZmlsZXMsICJ2YXJpYWJsZV9ncm91cHMiKSA8LSBwYXJhbXMkdmFyaWFibGVfZ3JvdXBzCiAgCiAgcGFycXVldF9maWxlIDwtCiAgICBwYXJxdWV0X2ZpbGVfcmVjb2RlZAogIAogIGZ1dGlsZS5sb2dnZXI6OmZsb2cuaW5mbyhnbHVlKCJXcml0aW5nIHtwYXJxdWV0X2ZpbGV9IC4uLiIpKQogIAogIHByb2ZpbGVzICU+JQogICAgd3JpdGVfcGFycXVldChwYXJxdWV0X2ZpbGUsCiAgICAgICAgICAgICAgICAgIGNvbXByZXNzaW9uID0gImd6aXAiLAogICAgICAgICAgICAgICAgICBjb21wcmVzc2lvbl9sZXZlbCA9IDkpCn0KYGBgCgojIFRyYW5zZm9ybQoKIyMgRnVuY3Rpb25zCgpgYGB7cn0KZ2V0X2JldGEgPC0gZnVuY3Rpb24oeCA9IDUsIHkgPSAwLjk5KSB7CiAgLWxvZygxIC8geSAtIDEpIC8geAp9CgphYnNfbG9naXN0aWMgPC0gZnVuY3Rpb24oeCwgYmV0YSA9IGdldF9iZXRhKCkpIHsKICAyIC8gKDEgKyBleHAoLWFicyh4KSAqIGJldGEpKSAtIDEKfQoKY3l0b21pbmVyX3ZhcmlhYmxlX2dyb3VwX2VucmljaG1lbnQgPC0KICBmdW5jdGlvbihwb3B1bGF0aW9uLAogICAgICAgICAgIHZhcmlhYmxlcywKICAgICAgICAgICB2YXJpYWJsZV9ncm91cHMsCiAgICAgICAgICAgc2lnbW9pZF9mdW5jdGlvbiA9IGFic19sb2dpc3RpYywKICAgICAgICAgICAuLi4pIHsKICAgIAogICAgdmFyaWFibGVzX2dyb3VwX2xpc3RzIDwtCiAgICAgIHZhcmlhYmxlX2dyb3VwcyAlPiUKICAgICAgdW5saXN0KCkgJT4lCiAgICAgIG5hbWVzKCkgJT4lCiAgICAgIHNldF9uYW1lcygpICU+JQogICAgICBwdXJycjo6bWFwKGZ1bmN0aW9uKHZhcmlhYmxlX2dyb3VwKSB7CiAgICAgICAgc3RyaW5ncjo6c3RyX3N1YnNldCh2YXJpYWJsZXMsIHZhcmlhYmxlX2dyb3VwKQogICAgICB9KSAKCiAgICBwb3B1bGF0aW9uX2RhdGFfdHJhbnNmb3JtZWQgPC0KICAgICAgdmFyaWFibGVzX2dyb3VwX2xpc3RzICU+JQogICAgICBtYXBfZGZjKGZ1bmN0aW9uKHZhcmlhYmxlc19ncm91cF9saXN0KSB7CiAgICAgICAgcG9wdWxhdGlvbiAlPiUKICAgICAgICAgIGRwbHlyOjpzZWxlY3QoYWxsX29mKHZhcmlhYmxlc19ncm91cF9saXN0KSkgJT4lCiAgICAgICAgICBkcGx5cjo6bXV0YXRlKGFjcm9zcyhhbGxfb2YodmFyaWFibGVzX2dyb3VwX2xpc3QpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbW9pZF9mdW5jdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLikpICU+JQogICAgICAgICAgZHBseXI6OnVuZ3JvdXAoKSAlPiUKICAgICAgICAgIGRwbHlyOjpyb3d3aXNlKCkgJT4lCiAgICAgICAgICBkcGx5cjo6dHJhbnNtdXRlKG5fYWJvdmUgPSByb3VuZChzdW0oCiAgICAgICAgICAgIGRwbHlyOjpjX2Fjcm9zcyhldmVyeXRoaW5nKCkpIC8KICAgICAgICAgICAgICBsZW5ndGgodmFyaWFibGVzX2dyb3VwX2xpc3QpLAogICAgICAgICAgICBuYS5ybSA9IFQKICAgICAgICAgICksIDIpKSAlPiUKICAgICAgICAgIGRwbHlyOjpwdWxsKG5fYWJvdmUpCiAgICAgIH0pCiAgICAKICAgIHBvcHVsYXRpb25fbWV0YWRhdGEgPC0KICAgICAgcG9wdWxhdGlvbiAlPiUKICAgICAgZHBseXI6OnNlbGVjdCgtYWxsX29mKHZhcmlhYmxlcykpCiAgICAKICAgIGVucmljaGVkIDwtCiAgICAgIGRwbHlyOjpiaW5kX2NvbHMocG9wdWxhdGlvbl9tZXRhZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2RhdGFfdHJhbnNmb3JtZWQpCiAgICAKICAgIGVucmljaGVkCiAgICAKICB9CmBgYAoKIyMgRXhlY3V0ZQoKYGBge3J9CnBhcnF1ZXRfZmlsZSA8LQogIGdsdWUoIntiYXRjaH0ve2ZpbGVuYW1lX3ByZWZpeF9wcm9maWxlc31fZW5yaWNoZWQucGFycXVldCIpCgppZiAoZmlsZS5leGlzdHMocGFycXVldF9maWxlKSAmICFwYXJhbXMkZm9yY2VfcmVjb21wdXRlKSB7CiAgZnV0aWxlLmxvZ2dlcjo6ZmxvZy5pbmZvKGdsdWUoIlJlYWRpbmcge3BhcnF1ZXRfZmlsZX0gLi4uIikpCiAgCiAgcHJvZmlsZXNfZW5yaWNoZWQgPC0KICAgIHJlYWRfcGFycXVldChwYXJxdWV0X2ZpbGUpCiAgCn0gZWxzZSB7CiAgCiAgcHJvZmlsZXNfZW5yaWNoZWQgPC0KICAgIHByb2ZpbGVzICU+JQogICAgZ3JvdXBfYnkoYWNyb3NzKHBhcmFtcyRzdHJhdGFfcmVwbGljYXRlKSkgJT4lCiAgICBzdW1tYXJpemUoYWNyb3NzKGFsbF9vZih2YXJpYWJsZXMpLCBtZWRpYW4pLCAuZ3JvdXBzID0gImtlZXAiKSAlPiUKICAgIGdyb3VwX2J5KGFjcm9zcyhwYXJhbXMkbmVzdGluZ19sZXZlbF8wKSkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIGN5dG9taW5lcl92YXJpYWJsZV9ncm91cF9lbnJpY2htZW50KAogICAgICAgIGN1cl9kYXRhX2FsbCgpLAogICAgICAgIHZhcmlhYmxlcyA9IHZhcmlhYmxlcywKICAgICAgICB2YXJpYWJsZV9ncm91cHMgPSBwYXJhbXMkdmFyaWFibGVfZ3JvdXBzCiAgICAgICksCiAgICAgIC5ncm91cHMgPSAia2VlcCIKICAgICkgJT4lCiAgICB1bmdyb3VwKCkKICAKICBhdHRyKHByb2ZpbGVzLCAidmFyaWFibGVfZ3JvdXBzIikgPC0gcGFyYW1zJHZhcmlhYmxlX2dyb3VwcwogIAogIGZ1dGlsZS5sb2dnZXI6OmZsb2cuaW5mbyhnbHVlKCJXcml0aW5nIHtwYXJxdWV0X2ZpbGV9IC4uLiIpKQogIAogIHByb2ZpbGVzX2VucmljaGVkICU+JQogICAgd3JpdGVfcGFycXVldChwYXJxdWV0X2ZpbGUsCiAgICAgICAgICAgICAgICAgIGNvbXByZXNzaW9uID0gImd6aXAiLAogICAgICAgICAgICAgICAgICBjb21wcmVzc2lvbl9sZXZlbCA9IDkpCiAgCn0KCnZhcmlhYmxlc19lbnJpY2hlZCA8LQogIHN0cl9zdWJzZXQobmFtZXMocHJvZmlsZXNfZW5yaWNoZWQpLCAiTWV0YWRhdGFfIiwgbmVnYXRlID0gVFJVRSkKYGBgCgojIFBsb3QKCmBgYHtyfQpwcm9maWxlc19lbnJpY2hlZCAlPiUgCiAgaW5uZXJfam9pbihleHBlcmltZW50KSAlPiUKICBwaXZvdF9sb25nZXIoLW1hdGNoZXMoIk1ldGFkYXRhIiksIAogICAgICAgICAgICAgICBuYW1lc190byA9ICJmZWF0dXJlX2dyb3VwIiklPiUgCiAgZ2dwbG90KGFlcyhmZWF0dXJlX2dyb3VwLCB2YWx1ZSkpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCmBgYAoKYGBge3J9CnByb2ZpbGVzX2VucmljaGVkICU+JSAKICBpbm5lcl9qb2luKGV4cGVyaW1lbnQpICU+JQogIHBpdm90X2xvbmdlcigtbWF0Y2hlcygiTWV0YWRhdGEiKSwgCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gImZlYXR1cmVfZ3JvdXAiKSAlPiUgCiAgZ2dwbG90KGFlcyhmZWF0dXJlX2dyb3VwLCB2YWx1ZSwgZ3JvdXAgPSBNZXRhZGF0YV9XZWxsKSkgKyAKICBnZW9tX2xpbmUoYWxwaGEgPSAuMDkpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArIAogIGZhY2V0X3dyYXAofk1ldGFkYXRhX25lZ2Nvbl9vcl9vdGhlciwgbmNvbCA9IDEpCmBgYApgYGB7ciBldmFsPVRSVUV9CmxpYnJhcnkocGxvdGx5KQoKZGYgPC0gCiAgcHJvZmlsZXNfZW5yaWNoZWQgJT4lCiAgaW5uZXJfam9pbihleHBlcmltZW50KQoKZGltZW5zaW9ucyA8LSBsaXN0KAogIGxpc3QobGFiZWwgPSAiSW50ZW5zaXR5X1JOQSIsCiAgICAgICB2YWx1ZXMgPSB+IEludGVuc2l0eV9STkEpLAogIGxpc3QobGFiZWwgPSAnSW50ZW5zaXR5X0ROQScsCiAgICAgICB2YWx1ZXMgPSB+IEludGVuc2l0eV9ETkEpCikKCmRpbWVuc2lvbnMgPC0KICB2YXJpYWJsZXNfZW5yaWNoZWQgJT4lCiAgbWFwKGZ1bmN0aW9uKHZhcmlhYmxlKSB7CiAgICBsaXN0KGxhYmVsID0gdmFyaWFibGUsCiAgICAgICAgIHZhbHVlcyA9IGRmW1t2YXJpYWJsZV1dKQogIH0pCgpkZiAlPiUKICBwbG90X2x5KHdpZHRoID0gMTAwMCwgCiAgICAgICAgICBoZWlnaHQgPSA2MDApICU+JQogIGFkZF90cmFjZSh0eXBlID0gJ3BhcmNvb3JkcycsCiAgICAgICAgICAgIGRpbWVuc2lvbnMgPSBkaW1lbnNpb25zKQpgYGAKCgoKCg==